package com.wuji.salary.controller;

import com.wuji.salary.dao.AlgorithmDao;
import com.wuji.salary.entity.Info;
import com.wuji.salary.entity.R;
import com.wuji.salary.entity.Salary;
import com.wuji.salary.entity.SalaryDTO;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Stack;

@RestController
public class CalculatorController {

    @Resource
    private AlgorithmDao algorithmDao;

    @PostMapping("/CustomizedSalary")
    public R test(@RequestBody(required = false) List<Salary> salaryList) throws Exception {
//        List<Salary> salaries = info.getSalaryList(); // 获取薪资列表
        ArrayList<SalaryDTO> list = new ArrayList<>(); // 创建一个用于存放结果的列表

        for (Salary salary : salaryList) {
            // 根据算法名称从数据库中查询对应的计算公式
            String formula = algorithmDao.getPayrollAlgorithmByName(salary.getPayrollAlgorithm());
            if (formula != null) {
                // 对公式进行预处理，添加空格以便于解析
                formula = preprocessFormula(formula);
                // 计算公式的结果
                BigDecimal result = evaluateExpression(formula, salary);
                System.out.println("Result: " + result);

                // 将计算结果赋值到 SalaryDTO 对象中
                SalaryDTO salaryDTO = new SalaryDTO();
                salaryDTO.setQsName(salary.getQsName()); // 设置企业名称
                salaryDTO.setJobNumber(salary.getJobNumber()); // 设置工号
                salaryDTO.setStatisticalMonth(salary.getStatisticalMonth()); // 设置统计月份
                salaryDTO.setQsSalary(result); // 设置计算出的薪资
                list.add(salaryDTO); // 将结果添加到列表中
            } else {
                return R.fail("算法不存在"); // 如果算法不存在，返回失败信息
            }
        }
        return R.ok(list); // 返回成功结果和薪资列表
    }

    // 预处理公式，添加空格以便于后续解析
    private String preprocessFormula(String formula) {
        StringBuilder processedFormula = new StringBuilder();
        for (char c : formula.toCharArray()) {
            // 如果是操作符或括号，添加空格
            if (isOperator(c) || c == '(' || c == ')') {
                processedFormula.append(" ").append(c).append(" ");
            } else {
                processedFormula.append(c); // 否则直接添加字符
            }
        }
        return processedFormula.toString().trim(); // 返回处理后的公式
    }

    // 判断字符是否为操作符
    private static boolean isOperator(char c) {
        return c == '+' || c == '-' || c == '*' || c == '/';
    }

    // 计算公式的结果
    private static BigDecimal evaluateExpression(String formula, Salary salary) throws Exception {
        Stack<BigDecimal> numbers = new Stack<>(); // 存放数字的栈
        Stack<Character> operators = new Stack<>(); // 存放操作符的栈
        int i = 0; // 初始化索引，指向公式字符串的当前字符位置

        while (i < formula.length()) {
            char c = formula.charAt(i); // 获取当前字符
            if (Character.isWhitespace(c)) { // 如果当前字符是空白字符
                i++; // 跳过空格，移动到下一个字符
                continue; // 继续下一次循环
            }

            // 处理数字
            if (Character.isDigit(c) || c == '.') { // 如果当前字符是数字或小数点
                StringBuilder numBuilder = new StringBuilder(); // 创建一个字符串构建器，用于构建数字
                while (i < formula.length() && (Character.isDigit(formula.charAt(i)) || formula.charAt(i) == '.')) {
                    numBuilder.append(formula.charAt(i)); // 将当前字符添加到数字构建器中
                    i++; // 移动到下一个字符
                }
                try {
                    // 将构建好的数字转换为 BigDecimal 并压入数字栈中
                    numbers.push(new BigDecimal(numBuilder.toString()));
                } catch (NumberFormatException e) {
                    throw new Exception("Invalid number format: " + numBuilder.toString(), e);
                }
            }
            // 处理属性名（字母）
            else if (Character.isLetter(c)) { // 如果当前字符是字母
                StringBuilder propertyName = new StringBuilder(); // 创建一个字符串构建器，用于构建属性名
                while (i < formula.length() && Character.isLetter(formula.charAt(i))) {
                    propertyName.append(formula.charAt(i)); // 将当前字符添加到属性名构建器中
                    i++; // 移动到下一个字符
                }
                try {
                    // 使用反射获取 Salary 对象中对应属性的值
                    BigDecimal value = getPropertyValue(propertyName.toString(), salary);
                    // 将获取到的属性值压入数字栈中
                    numbers.push(value);
                } catch (Exception e) {
                    throw new Exception("Error accessing property: " + propertyName.toString(), e);
                }
            }
            // 处理左括号
            else if (c == '(') { // 如果当前字符是左括号
                operators.push(c); // 将左括号压入操作符栈
                i++; // 移动到下一个字符
            }
            // 处理右括号
            else if (c == ')') { // 如果当前字符是右括号
                while (!operators.isEmpty() && operators.peek() != '(') {
                    processOperator(numbers, operators); // 处理栈中的操作符
                }
                if (operators.isEmpty()) {
                    throw new Exception("Mismatched parentheses: no matching '(' for ')'");
                }
                operators.pop(); // 移除左括号
                i++; // 移动到下一个字符
            }
            // 处理操作符
            else if (isOperator(c)) { // 如果当前字符是操作符
                while (!operators.isEmpty() && precedence(operators.peek()) >= precedence(c)) {
                    processOperator(numbers, operators); // 处理栈中的操作符
                }
                operators.push(c); // 将当前操作符压入栈中
                i++; // 移动到下一个字符
            }
        }
        // 处理剩余的操作符
        while (!operators.isEmpty()) {
            processOperator(numbers, operators); // 处理栈中的操作符
        }

        if (numbers.isEmpty()) {
            throw new Exception("No numbers to evaluate.");
        }

        return numbers.pop(); // 返回数字栈中的最终结果
    }

    // 通过反射获取 Salary 对象中特定属性的值
    private static BigDecimal getPropertyValue(String propertyName, Salary salary) throws Exception {
        Method getterMethod = Salary.class.getMethod("get" + capitalize(propertyName)); // 获取对应的 getter 方法
        return (BigDecimal) getterMethod.invoke(salary); // 调用 getter 方法并返回值
    }

    // 将字符串首字母大写
    private static String capitalize(String str) {
        return str.substring(0, 1).toUpperCase() + str.substring(1);
    }

    // 处理操作符的计算
    private static void processOperator(Stack<BigDecimal> numbers, Stack<Character> operators) {
        BigDecimal b = numbers.pop(); // 弹出栈顶的两个数字
        BigDecimal a = numbers.pop();
        char op = operators.pop(); // 弹出栈顶的操作符
        BigDecimal result;
        switch (op) {
            case '+':
                result = a.add(b); // 加法
                break;
            case '-':
                result = a.subtract(b); // 减法
                break;
            case '*':
                result = a.multiply(b); // 乘法
                break;
            case '/':
                result = a.divide(b); // 除法
                break;
            default:
                throw new IllegalArgumentException("无效的操作符: " + op); // 无效操作符异常
        }
        numbers.push(result); // 将计算结果压入数字栈中
    }

    // 返回操作符的优先级
    private static int precedence(char op) {
        if (op == '+' || op == '-') return 1; // 加法和减法优先级最低
        if (op == '*' || op == '/') return 2; // 乘法和除法优先级较高
        return 0; // 默认优先级为0
    }
}
